/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkRtmpUt.h"
#include "MkRtmp/MkRtmpServer.h"
#include "MkEvent/MkEvent.h"
#include "MkEvent/MkEventPool.h"
#include "MkEvent/MkTimer.h"
#include "MkUtil/MkUtil.h"
#include "MkMedia/MkFileSource.h"
#include "MkRtmp/MkRtmpPublisher.h"
#include "MkMedia/MkMediaConsumer.h"
#include "MkRtmp/MkRtmpPlayer.h"
#include "MkUtil/MkLog.h"
#include <gtest/gtest.h>
#ifndef _WIN32
#include "MkUtil/MkMemQueue.h"
#endif

CMkRtmpUt::CMkRtmpUt()
{

}

CMkRtmpUt::~CMkRtmpUt()
{

}

void CMkRtmpUt::SetUp()
{
    m_pRtmpServer = nullptr;
    m_pEventPool = nullptr;
    m_pTimer = nullptr;
    m_pH264FileSource = nullptr;
    m_pH265FileSource = nullptr;
    m_pAacFileSource = nullptr;
    m_pRtmpPublisher = nullptr;
    m_pRtmpPlayer = nullptr;
    m_pMediaConsume = nullptr;

    m_pEventPool = new CMkEventPool;
    m_pEventPool->Start();
    m_pTimer = new CMkTimer;
    m_pTimer->StartTimerThread();
    MkString H264FileName = MkString(MkUtSourcePath) + "/test.264";
    MkString H265FileName = MkString(MkUtSourcePath) + "/test.265";
    MkString AacFileName = MkString(MkUtSourcePath) + "/test.aac";
    FILE *fp264 = fopen(H264FileName.c_str(), "rb");
    FILE *fp265 = fopen(H265FileName.c_str(), "rb");
    FILE *fpAac = fopen(AacFileName.c_str(), "rb");

    m_pH264FileSource = new CMkH264FileSource(fp264, nullptr);
    m_pH265FileSource = new CMkH265FileSource(fp265, nullptr);
    m_pAacFileSource = new CMkAacFileSource(fpAac, nullptr);
    m_WaitHandle = CreateEvent(nullptr, FALSE, FALSE, nullptr);

    Uint32 ErrorCode = m_pH264FileSource->StartMediaSource(nullptr, nullptr);
    EXPECT_EQ(NoneError, ErrorCode);
    ErrorCode = m_pH265FileSource->StartMediaSource(nullptr, nullptr);
    EXPECT_EQ(NoneError, ErrorCode);
    ErrorCode = m_pAacFileSource->StartMediaSource(nullptr, nullptr);
    EXPECT_EQ(NoneError, ErrorCode);

    ErrorCode = m_pH264FileSource->GetNextFrame(m_VecPacket264);
    EXPECT_EQ(NoneError, ErrorCode);
    EXPECT_EQ(FALSE, m_VecPacket264.empty());

    ErrorCode = m_pH265FileSource->GetNextFrame(m_VecPacket265);
    EXPECT_EQ(NoneError, ErrorCode);
    EXPECT_EQ(FALSE, m_VecPacket265.empty());

    ErrorCode = m_pAacFileSource->GetNextFrame(m_VecPacketAac);
    EXPECT_EQ(NoneError, ErrorCode);
    EXPECT_EQ(FALSE, m_VecPacketAac.empty());

    MkMediaCallbacks MediaCbs;
    MediaCbs.GetSourceParamCb = [this](const MkString& Path, CMkVideoParam& VideoParam, CMkAudioParam& AudioParam, Uint32& Duration, Uint32& FileSize, MkString& SourceSession) {
        if ("/live/test264aac_play" == Path) {
            VideoParam = m_pH264FileSource->GetVideoParam();
            AudioParam = m_pAacFileSource->GetAudioParam();
            Duration = 1;
            FileSize = 100;
        } else if ("/live/test265aac_play" == Path) {
            VideoParam = m_pH265FileSource->GetVideoParam();
            AudioParam = m_pAacFileSource->GetAudioParam();
            Duration = 1;
            FileSize = 100;
        } else if ("/live/test264_play" == Path) {
            VideoParam = m_pH264FileSource->GetVideoParam();
            AudioParam = CMkAudioParam();
            Duration = 1;
            FileSize = 100;
        } else if ("/live/test265_play" == Path) {
            VideoParam = m_pH265FileSource->GetVideoParam();
            AudioParam = CMkAudioParam();
            Duration = 1;
            FileSize = 100;
        } else if ("/live/testAac_play" == Path) {
            VideoParam = CMkVideoParam();
            AudioParam = m_pAacFileSource->GetAudioParam();
            Duration = 1;
            FileSize = 100;
        } else {
            return SystemError;
        }
        SourceSession = Path;
        return NoneError;
    };

    MediaCbs.ConsumerAddCb = [this](const MkString& SourceSession, CMkMediaConsume* pConsume, CMkMediaConsumer* pConsumer) {
        m_pMediaConsume = pConsume;
        pConsume->AddConsumer(pConsumer);
        Uint8 pBuf[Len1K] = { 0 };
        CMkMediaSource MediaSource(MkMediaSourceFileFlv);
        if ("/live/test264aac_play" == SourceSession) {
            MediaSource.SetVideoParam(m_pH264FileSource->GetVideoParam());
            MediaSource.SetAudioParam(m_pAacFileSource->GetAudioParam());
            pConsume->ConsumeEsPacket(&MediaSource, *m_VecPacket264.begin(), pBuf, Len1K);
            pConsume->ConsumeEsPacket(&MediaSource, *m_VecPacketAac.begin(), pBuf, Len1K);
        } else if ("/live/test265aac_play" == SourceSession) {
            MediaSource.SetVideoParam(m_pH265FileSource->GetVideoParam());
            MediaSource.SetAudioParam(m_pAacFileSource->GetAudioParam());
            pConsume->ConsumeEsPacket(&MediaSource, *m_VecPacket265.begin(), pBuf, Len1K);
            pConsume->ConsumeEsPacket(&MediaSource, *m_VecPacketAac.begin(), pBuf, Len1K);
        } else if ("/live/test264_play" == SourceSession) {
            pConsume->ConsumeEsPacket(m_pH264FileSource, *m_VecPacket264.begin(), pBuf, Len1K);
        } else if ("/live/test265_play" == SourceSession) {
            pConsume->ConsumeEsPacket(m_pH265FileSource, *m_VecPacket265.begin(), pBuf, Len1K);
        } else if ("/live/testAac_play" == SourceSession) {
            pConsume->ConsumeEsPacket(m_pAacFileSource, *m_VecPacketAac.begin(), pBuf, Len1K);
        }
        return NoneError;
    };
    MediaCbs.SourceAddCb = [](CMkMediaSource* pSource) {
        return NoneError;
    };
    MediaCbs.ConsumerClosedCb = [this](const MkString& SourceSession, const MkMediaConsumeType& ConsumeType, const MkString& ConsumerSession) {
        if (m_pMediaConsume)
        {
            m_pMediaConsume->DeleteConsumer(ConsumerSession);

        }
        return NoneError;
    };
    MediaCbs.SourceDeleteCb = [](const MkString& SourceSession) {
        return NoneError;
    };

    m_pRtmpServer = new CMkRtmpServer(m_pEventPool, m_pTimer, MediaCbs);
    while (1) {
        m_ServerPort = CMkUtil::GetRandomNumber() % 0xFFFF;
        if (NoneError == m_pRtmpServer->StartServer(m_ServerPort)) {
            break;
        }
    }
}

void CMkRtmpUt::TearDown()
{
    CMkThread::ThreadSleep(100);
    m_pTimer->StopTimerThread();
    m_pEventPool->Stop();
    MkDelete(m_pRtmpServer);
    MkDelete(m_pTimer);
    MkDelete(m_pEventPool);
    MkDelete(m_pH264FileSource);
    MkDelete(m_pH265FileSource);
    MkDelete(m_pAacFileSource);
    MkDelete(m_pRtmpPublisher);
    MkDelete(m_pRtmpPlayer);
    CloseHandle(m_WaitHandle);
    MkDelete(m_pMediaConsume);
}

TEST_F(CMkRtmpUt, Publish264AacTest)
{
    m_pRtmpPublisher = new CMkRtmpPublisher(m_pEventPool->GetFreeEvent(), m_pTimer, [this](CMkTcpClient* pClient) {
        pClient->DeleteLater();
        m_pRtmpPublisher = nullptr;
        SetEvent(m_WaitHandle);
    });
    m_pRtmpPublisher->Start("rtmp://127.0.0.1:" + std::to_string(m_ServerPort) + "/live/test264aac", m_pH264FileSource->GetVideoParam(), m_pAacFileSource->GetAudioParam(), 0, 0, [this]() {
        if (m_pRtmpPublisher) {
            for (int i = 0; i < 10; i++) {
                m_pRtmpPublisher->SendEsPacket(*m_VecPacket264.begin());
                m_pRtmpPublisher->SendEsPacket(*m_VecPacketAac.begin());
            }
            m_pRtmpPublisher->Close();
        }
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkRtmpUt, Publish265AacTest)
{
    m_pRtmpPublisher = new CMkRtmpPublisher(m_pEventPool->GetFreeEvent(), m_pTimer, [this](CMkTcpClient* pClient) {
        pClient->DeleteLater();
        m_pRtmpPublisher = nullptr;
        SetEvent(m_WaitHandle);
    });
    m_pRtmpPublisher->Start("rtmp://127.0.0.1:" + std::to_string(m_ServerPort) + "/live/test265aac", m_pH265FileSource->GetVideoParam(), m_pAacFileSource->GetAudioParam(), 0, 0, [this]() {
        if (m_pRtmpPublisher) {
            for (int i = 0; i < 10; i++) {
                m_pRtmpPublisher->SendEsPacket(*m_VecPacket265.begin());
                m_pRtmpPublisher->SendEsPacket(*m_VecPacketAac.begin());
            }
            m_pRtmpPublisher->Close();
        }
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkRtmpUt, Publish265Test)
{
    m_pRtmpPublisher = new CMkRtmpPublisher(m_pEventPool->GetFreeEvent(), m_pTimer, [this](CMkTcpClient* pClient) {
        pClient->DeleteLater();
        m_pRtmpPublisher = nullptr;
        SetEvent(m_WaitHandle);
    });
    m_pRtmpPublisher->Start("rtmp://127.0.0.1:" + std::to_string(m_ServerPort) + "/live/test265", m_pH265FileSource->GetVideoParam(), CMkAudioParam(), 0, 0, [this]() {
        if (m_pRtmpPublisher) {
            for (int i = 0; i < 10; i++) {
                m_pRtmpPublisher->SendEsPacket(*m_VecPacket265.begin());
            }
            m_pRtmpPublisher->Close();
        }
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkRtmpUt, Publish264Test)
{
    m_pRtmpPublisher = new CMkRtmpPublisher(m_pEventPool->GetFreeEvent(), m_pTimer, [this](CMkTcpClient* pClient) {
        pClient->DeleteLater();
        m_pRtmpPublisher = nullptr;
        SetEvent(m_WaitHandle);
    });
    m_pRtmpPublisher->Start("rtmp://127.0.0.1:" + std::to_string(m_ServerPort) + "/live/test264", m_pH264FileSource->GetVideoParam(), CMkAudioParam(), 0, 0, [this]() {
        if (m_pRtmpPublisher) {
            for (int i = 0; i < 10; i++) {
                m_pRtmpPublisher->SendEsPacket(*m_VecPacket264.begin());
            }
            m_pRtmpPublisher->Close();
        }
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkRtmpUt, PublishAacTest)
{
    m_pRtmpPublisher = new CMkRtmpPublisher(m_pEventPool->GetFreeEvent(), m_pTimer, [this](CMkTcpClient* pClient) {
        pClient->DeleteLater();
        m_pRtmpPublisher = nullptr;
        SetEvent(m_WaitHandle);
    });
    m_pRtmpPublisher->Start("rtmp://127.0.0.1:" + std::to_string(m_ServerPort) + "/live/testAac", CMkVideoParam(), m_pAacFileSource->GetAudioParam(), 0, 0, [this]() {
        if (m_pRtmpPublisher) {
            for (int i = 0; i < 10; i++) {
                m_pRtmpPublisher->SendEsPacket(*m_VecPacketAac.begin());
            }
            m_pRtmpPublisher->Close();
        }
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkRtmpUt, Player264AacTest)
{
    m_pRtmpPlayer = new CMkRtmpPlayer(m_pEventPool->GetFreeEvent(), m_pTimer, [this](CMkTcpClient* pClient) {
        pClient->DeleteLater();
        m_pRtmpPlayer = nullptr;
        SetEvent(m_WaitHandle);
        MkDebugLog("set event\n");
    });
    m_pRtmpPlayer->StartMediaSource("rtmp://127.0.0.1:" + std::to_string(m_ServerPort) + "/live/test264aac_play", [this](CMkMediaSource* pSource, Uint32 ErrorCode) {
        EXPECT_EQ(NoneError, ErrorCode);
        return NoneError;
    }, [this](const MkEsPacket& EsPacket, const CMkVideoParam& VideoParam, const CMkAudioParam& AudioParam) {
        EXPECT_EQ(VideoParam.GetCodec(), MkCodecH264);
        EXPECT_EQ(AudioParam.GetCodec(), MkCodecAac);
        if (m_pRtmpPlayer) {
            m_pRtmpPlayer->StopMediaSource();
        }
        m_pRtmpPlayer = nullptr;
        return NoneError;
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkRtmpUt, Player265AacTest)
{
    m_pRtmpPlayer = new CMkRtmpPlayer(m_pEventPool->GetFreeEvent(), m_pTimer, [this](CMkTcpClient* pClient) {
        pClient->DeleteLater();
        m_pRtmpPlayer = nullptr;
        SetEvent(m_WaitHandle);
    });
    m_pRtmpPlayer->StartMediaSource("rtmp://127.0.0.1:" + std::to_string(m_ServerPort) + "/live/test265aac_play", [this](CMkMediaSource* pSource, Uint32 ErrorCode) {
        EXPECT_EQ(NoneError, ErrorCode);
        return NoneError;
    }, [this](const MkEsPacket& EsPacket, const CMkVideoParam& VideoParam, const CMkAudioParam& AudioParam) {
        EXPECT_EQ(VideoParam.GetCodec(), MkCodecH265);
        EXPECT_EQ(AudioParam.GetCodec(), MkCodecAac);
        if (m_pRtmpPlayer) {
            m_pRtmpPlayer->StopMediaSource();
        }
        m_pRtmpPlayer = nullptr;
        return NoneError;
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkRtmpUt, PlayerAacTest)
{
    m_pRtmpPlayer = new CMkRtmpPlayer(m_pEventPool->GetFreeEvent(), m_pTimer, [this](CMkTcpClient* pClient) {
        pClient->DeleteLater();
        m_pRtmpPlayer = nullptr;
        SetEvent(m_WaitHandle);
    });
    m_pRtmpPlayer->StartMediaSource("rtmp://127.0.0.1:" + std::to_string(m_ServerPort) + "/live/testAac_play", [this](CMkMediaSource* pSource, Uint32 ErrorCode) {
        EXPECT_EQ(NoneError, ErrorCode);
        return NoneError;
    }, [this](const MkEsPacket& EsPacket, const CMkVideoParam& VideoParam, const CMkAudioParam& AudioParam) {
        EXPECT_EQ(VideoParam.GetCodec(), MkCodecUnknown);
        EXPECT_EQ(AudioParam.GetCodec(), MkCodecAac);
        if (m_pRtmpPlayer) {
            m_pRtmpPlayer->StopMediaSource();
        }
        m_pRtmpPlayer = nullptr;
        return NoneError;
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkRtmpUt, Player264Test)
{
    m_pRtmpPlayer = new CMkRtmpPlayer(m_pEventPool->GetFreeEvent(), m_pTimer, [this](CMkTcpClient* pClient) {
        pClient->DeleteLater();
        m_pRtmpPlayer = nullptr;
        SetEvent(m_WaitHandle);
    });
    m_pRtmpPlayer->StartMediaSource("rtmp://127.0.0.1:" + std::to_string(m_ServerPort) + "/live/test264_play", [this](CMkMediaSource* pSource, Uint32 ErrorCode) {
        EXPECT_EQ(NoneError, ErrorCode);
        return NoneError;
    }, [this](const MkEsPacket& EsPacket, const CMkVideoParam& VideoParam, const CMkAudioParam& AudioParam) {
        EXPECT_EQ(VideoParam.GetCodec(), MkCodecH264);
        EXPECT_EQ(AudioParam.GetCodec(), MkCodecUnknown);
        if (m_pRtmpPlayer) {
            m_pRtmpPlayer->StopMediaSource();
        }
        m_pRtmpPlayer = nullptr;
        return NoneError;
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkRtmpUt, Player265Test)
{
    m_pRtmpPlayer = new CMkRtmpPlayer(m_pEventPool->GetFreeEvent(), m_pTimer, [this](CMkTcpClient* pClient) {
        pClient->DeleteLater();
        m_pRtmpPlayer = nullptr;
        SetEvent(m_WaitHandle);
    });
    m_pRtmpPlayer->StartMediaSource("rtmp://127.0.0.1:" + std::to_string(m_ServerPort) + "/live/test265_play", [this](CMkMediaSource* pSource, Uint32 ErrorCode) {
        EXPECT_EQ(NoneError, ErrorCode);
        return NoneError;
    }, [this](const MkEsPacket& EsPacket, const CMkVideoParam& VideoParam, const CMkAudioParam& AudioParam) {
        EXPECT_EQ(VideoParam.GetCodec(), MkCodecH265);
        EXPECT_EQ(AudioParam.GetCodec(), MkCodecUnknown);
        if (m_pRtmpPlayer) {
            m_pRtmpPlayer->StopMediaSource();
        }
        m_pRtmpPlayer = nullptr;
        return NoneError;
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}